#include "myiic.h"
#include "gd32f20x_eval.h"
#include "gd32f20x.h"
#include "main.h"
#include "systick.h"
#include <rtthread.h>

/**
 * @brief 延时约1微秒（基于8MHz主频）
 */
void delay_us(uint32_t us)
{
    uint32_t i;
    while(us--)
    {
        // 假设主频为8MHz，每条指令约0.125us
        // for循环大致会消耗 ~8 次 __NOP() 的时间
        for(i = 0; i < 8; i++)
        {
            __NOP();  // 空操作，占用1个时钟周期
        }
    }
}

/**
 * @brief       IIC延时函数,用于控制IIC读写速度
 * @param       无
 * @retval      无
 */
static void iic_delay(void)
{
		delay_us(10);
}

/**
 * @brief       产生IIC起始信号
 * @param       无
 * @retval      无
 */
void iic_start(_myiic_t *i2c)
{
    IIC_SDA(i2c,1);
    IIC_SCL(i2c,1);
    iic_delay();
    IIC_SDA(i2c,0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL(i2c,0);     /* 钳住I2C总线，准备发送或接收数据 */
    iic_delay();
}

/**
 * @brief       产生IIC停止信号
 * @param       无
 * @retval      无
 */
void iic_stop(_myiic_t *i2c)
{
    IIC_SDA(i2c,0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL(i2c,1);
    iic_delay();
    IIC_SDA(i2c,1);     /* 发送I2C总线结束信号 */
    iic_delay();
}

/**
 * @brief       等待应答信号到来
 * @param       无
 * @retval      1，接收应答失败
 *              0，接收应答成功
 */
uint8_t iic_wait_ack(_myiic_t *i2c)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;

    IIC_SDA(i2c,1);     /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    iic_delay();
    IIC_SCL(i2c,1);     /* SCL=1, 此时从机可以返回ACK */
    iic_delay();

    while (IIC_READ_SDA(i2c))    /* 等待应答 */
    {
        waittime++;
        if (waittime > 250)
        {
            iic_stop(i2c);
            rack = 1;
            break;
        }
    }

    IIC_SCL(i2c,0);     /* SCL=0, 结束ACK检查 */
    iic_delay();
    return rack;
}

/**
 * @brief       产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_ack(_myiic_t *i2c)
{
    IIC_SDA(i2c,0);     /* SCL 0 -> 1 时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL(i2c,1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(i2c,0);
    iic_delay();
    IIC_SDA(i2c,1);     /* 主机释放SDA线 */
    iic_delay();
}

/**
 * @brief       不产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_nack(_myiic_t *i2c)
{
    IIC_SDA(i2c,1);     /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    iic_delay();
    IIC_SCL(i2c,1);     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL(i2c,0);
    iic_delay();
}

/**
 * @brief       IIC发送一个字节
 * @param       data: 要发送的数据
 * @retval      无
 */
void iic_send_byte(_myiic_t *i2c,uint8_t data)
{
    uint8_t t;
    
    for (t = 0; t < 8; t++)
    {
        IIC_SDA(i2c,(data & 0x80) >> 7);    /* 高位先发送 */
        iic_delay();
        IIC_SCL(i2c,1);
        iic_delay();
        IIC_SCL(i2c,0);
        data <<= 1;     /* 左移1位,用于下一次发送 */
    }
    IIC_SDA(i2c,1);         /* 发送完成, 主机释放SDA线 */
}

/**
 * @brief       IIC读取一个字节
 * @param       ack:  ack=1时，发送ack; ack=0时，发送nack
 * @retval      接收到的数据
 */
uint8_t iic_read_byte(_myiic_t *i2c, uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */
    {
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL(i2c,1);
        iic_delay();

        if (IIC_READ_SDA(i2c))
        {
            receive++;
        }
        
        IIC_SCL(i2c,0);
        iic_delay();
    }

    if (!ack)
    {
        iic_nack(i2c);     /* 发送nACK */
    }
    else
    {
        iic_ack(i2c);      /* 发送ACK */
    }

    return receive;
}




